
#include "Debug.h"
#include "Log.h"
#include "simple_protocol.h"
#include "utility.h"
#include <Reader/Reader.h>

enum {
	API_NTAG_READ = 0,
	API_NTAG_WRITE = 1,
	API_NTAG_FASTREAD = 2,
	API_NTAG_READCOUNTER = 3,
	API_NTAG_READSIG = 4,
	API_NTAG_GETVERSION = 5,
	API_NTAG_PWDAUTH = 6,
	API_NTAG_SECTORSELECT = 7,
	API_NTAG_NUM,
};

phStatus_t ntag_read(uint8_t page, uint8_t *data){
	void *psalMFUL = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_Read(psalMFUL, page, data);
}

phStatus_t ntag_write(uint8_t page, uint8_t *data){
	void *psalMFUL = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_Write(psalMFUL, page, data);
}

phStatus_t ntag_fast_read(uint8_t pageStart, uint8_t num, uint8_t *data){
	if(num == 0){
		LOG_W("num == 0!");
		return 0;
	}
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	uint8_t* buf;
	uint16_t nBytes = 0;
	uint8_t pageEnd = pageStart + num - 1;
	phStatus_t status = phalMful_FastRead(palMful, pageStart, pageEnd, &buf, &nBytes);
	if(status){
		return status;
	}
	memcpy(data, buf, nBytes);
	return status;
}

phStatus_t ntag_read_counter(uint8_t counterAddr, uint8_t* incrValue){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_ReadCnt(palMful, counterAddr, incrValue);
}

phStatus_t ntag_read_sig(uint8_t* sig, uint16_t *sigLen){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	uint8_t* pSign;
	phStatus_t status = phalMful_ReadSign(palMful, 0x00, &pSign, sigLen);
	if(status){
		return status;
	}
	memcpy(sig, pSign, *sigLen);
	return status;
}

phStatus_t ntag_get_version(uint8_t* ver, uint8_t *vLen){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	phStatus_t status = phalMful_GetVersion(palMful, ver);
	if(status){
		return status;
	}
	*vLen = 8;
	return status;
}

phStatus_t ntag_pwd_pwd(uint8_t *pwd, uint8_t* pack){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	
	return phalMful_PwdAuth(palMful, pwd, pack);
}


phStatus_t ntag_sectorselect(uint8_t bsecNo){
	void *psalMFUL = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_SectorSelect(psalMFUL, bsecNo);
}

/*============================================================*/
/*
1.5.26.1. NTAG_Read
Command: [2000][Byte: Page]
Response: [00][Bool: Result][Byte Array(16): Page]
Example
Command: 200004
(Page: 04)
Response: 000103B691028C537091016855016E78702E
(Result: true, Page: 03B691028C537091016855016E78702E)
*/
static int api_ntag_read	(buffer_t* command, buffer_t* response){
	uint8_t page = net_buf_simple_pull_u8(command);
	uint8_t* data = net_buf_simple_tail(response);
	phStatus_t status = ntag_read(page, data);
	API_CHECK(status);
	net_buf_simple_add(response, 16);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.26.2. NTAG_Write
Command: [2001][Byte: Page][Byte Array(4): Data]
Response: [00][Bool: Result]
Example
Command: 20010400000000
(Page: 04, Data: 00000000)
Response: 0001
(Result: true)
*/
static int api_ntag_write	(buffer_t* command, buffer_t* response){
	
#pragma pack(1)
	typedef struct {
		uint8_t Page;
		uint8_t Data[4];
	}ntag_write_param_t;	
#pragma pack()

	ntag_write_param_t* param = (ntag_write_param_t*) command->data;
	phStatus_t status = ntag_write(param->Page, param->Data);
	API_CHECK(status);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.26.3. NTAG_FastRead
Command: [2002][Byte: StartPage][Byte: NumberOfPages]
Response: [00][Bool: Result][Byte Array(Var): Data]
Example
Command: 20020401
(StartPage: 04, NumberOfPages: 01)
Response: 00010403B69102
(Result: true, Data: 03B69102)
*/
static int api_ntag_fastread(buffer_t* command, buffer_t* response){
#pragma pack(1)
	typedef struct {
		uint8_t StartPage;
		uint8_t NumberOfPages;
	}ultralight_fast_read_param_t;
#pragma pack()
	ultralight_fast_read_param_t* param = (ultralight_fast_read_param_t*) command->data;
	LOGD(NULL, "StartPage=%d,NumberOfPages=%d", param->StartPage, param->NumberOfPages);
	uint8_t* data = net_buf_simple_tail(response);
	phStatus_t status = ntag_fast_read(param->StartPage, param->NumberOfPages, data);
	API_CHECK(status);
	uint16_t dlen = param->NumberOfPages * 4;
	LOG_SBUF("data", data, dlen);
	net_buf_simple_push_u8(response, (uint8_t)dlen);
	net_buf_simple_add(response, dlen);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.26.4. NTAG_ReadCounter
Command: [2003]
Response: [00][Bool: Result][UInt32: CounterValue]
Example
Command: 2003
Response: 000101000000
(Result: true, CounterValue: 1)
*/
static int api_ntag_readcounter	(buffer_t* command, buffer_t* response){
	uint8_t* data = net_buf_simple_tail(response);
	memset(data, 0, 4);
	phStatus_t status = ntag_read_counter(0x02, data);
	API_CHECK(status);
	net_buf_simple_add(response, 4);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.26.5. NTAG_ReadSig
Command: [2004]
Response: [00][Bool: Result][Byte Array(32): ECCSig]
Example
Command: 2004
Response: 0001A9AC15AFB52080BA26A45B1DA442F363E31B41271AB12B3E6F67-
864615B05321
(Result: true, ECCSig:
A9AC15AFB52080BA26A45B1DA442F363E31B41271AB12B3E6F67864615B05321)
*/
static int api_ntag_readsig	(buffer_t* command, buffer_t* response){
	uint8_t* data = net_buf_simple_tail(response);
	uint16_t sigLen;
	phStatus_t status = ntag_read_sig(data, &sigLen);
	API_CHECK(status);
	LOG_SBUF("Sign", data, sigLen);
	net_buf_simple_add(response, sigLen);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.26.6. NTAG_GetVersion
Command: [2005]
Response: [00][Bool: Result][Byte Array(8): Version]
Example
Command: 2005
Response: 00010004040502011503
(Result: true, Version: 0004040502011503)
*/
static int api_ntag_getversion	(buffer_t* command, buffer_t* response){
	uint8_t* data = net_buf_simple_tail(response);
	uint8_t vLen;
	phStatus_t status = ntag_get_version(data, &vLen);
	API_CHECK(status);
	LOG_SBUF("Version", data, vLen);
	net_buf_simple_add(response, vLen);
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
/*
1.5.26.7. NTAG_PwdAuth
Command: [2006][Byte Array(4): Password][Byte Array(2): PwdAck]
Response: [00][Bool: Result]
Example
Command: 2006FFFFFFFF0000
(Password: FFFFFFFF, PwdAck: 0000)
Response: 0001
(Result: true)
*/
static int api_ntag_pwdauth(buffer_t * command, buffer_t * response)	{
#pragma pack(1)
	typedef struct {
		uint8_t Pwd[4];
		uint8_t PwdAck[2];
	}ntag_authenticate_pwd_param_t;
#pragma pack()

	ntag_authenticate_pwd_param_t* param = (ntag_authenticate_pwd_param_t*) command->data;
	LOG_SBUF("Pwd", param->Pwd, sizeof(param->Pwd));
	LOG_SBUF("PwdAck", param->PwdAck, sizeof(param->PwdAck));
	uint8_t pack[2] = {0};
	phStatus_t status = ntag_pwd_pwd(param->Pwd, pack);
	API_CHECK(status);
	LOG_SBUF("pack", pack, 2);
	if(memcmp(param->PwdAck, pack, sizeof(param->PwdAck))){
		LOG_E("pack error!!");
		return -2;
	}
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.26.8. NTAG_SectorSelect
Command: [2007][Byte: Sector]
Response: [00][Bool: Result]
Example
Command: 200700
(Sector: 00)
Response: 0001
(Result: true)
*/
static int api_ntag_sectorselect(buffer_t* command, buffer_t* response){
	uint8_t secno = net_buf_simple_pull_u8(command);
	phStatus_t status = ntag_sectorselect(secno);
	uint8_t result = status ? 0 : 1;
	net_buf_simple_push_u8(response, result);
	return ERR_NONE;
}

static const api_entry_t api_ntag_list[API_NTAG_NUM] = {
	[API_NTAG_READ] = api_ntag_read,
	[API_NTAG_WRITE] = api_ntag_write,
	[API_NTAG_FASTREAD] = api_ntag_fastread,
	[API_NTAG_READCOUNTER] = api_ntag_readcounter,
	[API_NTAG_READSIG] = api_ntag_readsig,
	[API_NTAG_GETVERSION] = api_ntag_getversion,
	[API_NTAG_PWDAUTH] = api_ntag_pwdauth,
	[API_NTAG_SECTORSELECT] = api_ntag_sectorselect,
};
	
static int ntag_call_api(buffer_t* command, buffer_t* response){
	uint8_t fun = net_buf_simple_pull_u8(command);
	const uint8_t fun_num = sizeof(api_ntag_list)/sizeof(api_ntag_list[0]);
	if(fun < fun_num){
		return api_ntag_list[fun](command, response);
	}
	return ERR_INVALID_FUNCTION;
}

static int ntag_api(buffer_t* command, buffer_t* response){
	int ret = ntag_call_api(command, response);
	if(ret > 0){
		return ret;
	}
	protocol_response_result(response, ret);
	return ERR_NONE;
}


SIMPLE_API_DEFINE(API_CLASS_NTAG, ntag_api);



